﻿
//
// 部分api文档地址：https://miniblink.net/views/doc/api-doc-vip.html
// 目前已导出的api:
// mbInit
// mbUninit
// mbCreateInitSettings
// mbSetInitSettings
// mbCreateWebWindow
// mbOnLoadUrlBegin
// mbOnTitleChanged
// mbOnURLChanged
// mbOnCreateView
// mbOnConsole
// mbLoadURL
// mbShowWindow
// mbRunMessageLoop
// mbExitMessageLoop
// mbPostToUiThread
// mbGetString
// mbGetStringLen
// mbDeleteString
// mbCreateString
// mbNetSetData
// mbNetSetMIMEType
// mbNetSetHTTPHeaderFieldUtf8
// mbIsMainFrame
// mbReload
// mbGoForward
// mbGoBack
// mbResize
// mbGetSize
// mbWake
// mbDestroyWebView
// mbNetCancelRequest
// mbPopupDialogAndDownload
// mbOnDownloadInBlinkThread
// mbOnPrinting
// mbSetNavigationToNewWindowEnable
// mbOnClose
// mbQueryState
// mbNetChangeRequestUrl
// mbRunJs
// mbWebFrameGetMainFrame
// mbResponseQuery
// mbOnJsQuery
// mbCreateWebView
// mbOnPaintUpdated
// mbGetHostHWND
// mbMoveToCenter
// mbSetHandle
// mbSetFocus
// mbKillFocus
// mbSetDebugConfig
// mbJsToBoolean
// mbJsToDouble
// mbJsToString
// mbGetLockedViewDC
// mbUnlockViewDC
// mbOnLoadingFinish
// mbOnLoadUrlEnd
// mbOnDocumentReady
// mbOnDownload
// mbOnAlertBox
// mbOnConfirmBox
// mbOnPromptBox
// mbOnImageBufferToDataURL
// mbOnNavigation
// mbOnDidCreateScriptContext
// mbSetCspCheckEnable
// mbSetCookieEnabled
// mbFireKeyDownEvent
// mbFireKeyPressEvent
// mbFireKeyUpEvent
// mbFireMouseWheelEvent
// mbFireWindowsMessage
// mbFireMouseEvent
// mbSetResourceGc
// mbSetUserKeyValue
// mbGetUserKeyValue
// mbGetSource
// mbGetSize

#include <vector>
#include <signal.h>
#include <miniblink/mb.h>
#include <windows.h>
#include <windowsx.h>
#include <WinUser.h>
#include <stdio.h>
#include <string.h>
#include <Dwmapi.h>
 
#pragma comment(lib, "dwmapi.lib")
#pragma comment(lib, "UxTheme.lib")

const char* kHtmlTestStr =
"<!DOCTYPE html>"
"<html lang=\"en\">"
"<head>"
"    <meta charset=\"UTF-8\">"
"    <meta name=\"viewport\" content=\"width=device-width, initial-scale = 1.0\">"
"    <title>test</title>"
"    <style>"
"        .center {"
"            display: flex;"
"            justify-content: center;"
"            align-items: center;"
"            height: 100vh;"
"        }"
"    </style>"
"    <script type=\"text/javascript\">"
"        function onClose(customMsg, response) {alert(\"response:\" + response);}"
"        function OnClick() {window.mbQuery(0x7190, \"test message\", onClose);}"
"    </script>"
"</head>"
"<body>"
"    <div class=\"center\"><button onclick=\"OnClick()\">close</button></div>"
"</body>"
"</html>";

extern "C" unsigned long _stack_chk_guard;

typedef LRESULT(CALLBACK* WEBVIEWWNDPROC)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
WEBVIEWWNDPROC g_WebViewWndOldProc; // 用来备份旧的游戏窗口过程
HWND         g_hWebViewWnd;
static RECT  border_thickness;

LRESULT CALLBACK MyGameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    WORD wTmpBuffer = 0;
    if (hWnd == g_hWebViewWnd)
    {
        switch (uMsg)
        {
        case WM_NCCALCSIZE:
        {
            if (lParam) {
                NCCALCSIZE_PARAMS* sz = (NCCALCSIZE_PARAMS*)lParam;
                sz->rgrc[0].left += border_thickness.left;
                sz->rgrc[0].right -= border_thickness.right;
                sz->rgrc[0].bottom -= border_thickness.bottom;
                return 0;
            }
            break;
        }
        case WM_NCHITTEST:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ScreenToClient(hWnd, &pt);
            RECT rc;
            GetClientRect(hWnd, &rc);
            enum { left = 1, top = 2, right = 4, bottom = 8, caption = 16 };
            int hit = 0;
            if (pt.x < border_thickness.left) hit |= left;
            if (pt.x > rc.right - border_thickness.right) hit |= right;
            if (pt.y < border_thickness.top) hit |= top;
            if (pt.y > rc.bottom - border_thickness.bottom) hit |= bottom;
    
            //设置窗口头部30个像素可以用来拖动
            if (pt.y > border_thickness.top && pt.y < border_thickness.top + 30) hit |= caption;
    
            if (hit & top && hit & left) return HTTOPLEFT;
            if (hit & top && hit & right) return HTTOPRIGHT;
            if (hit & bottom && hit & left) return HTBOTTOMLEFT;
            if (hit & bottom && hit & right) return HTBOTTOMRIGHT;
            if (hit & left) return HTLEFT;
            if (hit & top) return HTTOP;
            if (hit & right) return HTRIGHT;
            if (hit & bottom) return HTBOTTOM;
            if (hit & caption) return HTCAPTION;
    
            return HTCLIENT;
        }
        }
    }

    return CallWindowProc(g_WebViewWndOldProc, hWnd, uMsg, wParam, lParam);
}

mbWebView MB_CALL_TYPE handleCreateView(mbWebView webView, void* param, mbNavigationType navigationType, const utf8* url, const mbWindowFeatures* windowFeatures)
{
    printf("handleLoadUrlBegin: %s \n", url);
    mbWebView mbView = mbCreateWebWindow(MB_WINDOW_TYPE_POPUP, NULL, 110, 60, 600, 700);
    ::mbOnCreateView(mbView, handleCreateView, nullptr);
    ::mbSetNavigationToNewWindowEnable(mbView, true);
    ::mbSetCspCheckEnable(mbView, true);

    ::mbShowWindow(mbView, TRUE);
    return mbView;
}

BOOL MB_CALL_TYPE handleWindowClose(mbWebView webView, void* param, void* unuse)
{
    ::mbExitMessageLoop();
    return TRUE;
}

static BOOL MB_CALL_TYPE handleLoadUrlBegin(mbWebView webView, void* param, const char* url, void* job)
{
    printf("handleLoadUrlBegin: %s \n", url);
    //     std::string urlStr("handleLoadUrlBegin:");
    //     urlStr += url;
    //     urlStr += "\n";
    //     printf(urlStr.c_str());
    //
    //     if (hookUrl(job, url, "universal-report.min.js", L"G:\\test\\web_test\\51iwifi\\universal-report.min.js", "text/html"))
    //         return true;
    // 
    //     if (hookUrl(job, url, "_app-f54e3843f15fa10c7198.js", L"D:\\test\\web\\cc_163\\_app-f54e3843f15fa10c7198.js", "text/javascript"))
    //         return true;
    // 
    //     if (hookUrl(job, url, "act/webcc/link-pk-game/v1.9.1/index.js", L"D:\\test\\web\\cc_163\\webcc_191_index.js", "text/javascript"))
    //         return true;
    // 
    //     if (hookUrl(job, url, "act/webcc/performance-reporter/v1.2.0/index.js", L"D:\\test\\web\\cc_163\\performance-reporter.js", "text/javascript"))
    //         return true;
    // 
    //     if (0 != strstr(url, "mini_original.js?v")) {
    //         mbNetChangeRequestUrl(job, "http://192.168.83.1:8080/mini_original.js");
    //     }
    return TRUE;
}

void MB_CALL_TYPE onJsQueryCallback(mbWebView webView, void* param, mbJsExecState es, int64_t queryId, int customMsg, const utf8* request)
{
    printf("onJsQueryCallback: custiomMsg: %X, request: %s \n", customMsg, request);

    if (customMsg == 0x7190) {
        PostMessage(g_hWebViewWnd, WM_CLOSE, 0, 0);
    }
    ::mbResponseQuery(webView, queryId, customMsg, "I am response");
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
// int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
    mbInit(nullptr);

    // mbWebView mbView = mbCreateWebWindow(MB_WINDOW_TYPE_POPUP, NULL, 100, 50, 600, 700); // 创建一个普通窗口
    mbWebView mbView = ::mbCreateWebCustomWindow(NULL, WS_VISIBLE | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 0, 100, 50, 600, 700); // 创建了一个无标题栏无边框的窗口

    ::mbSetWindowTitle(mbView, "miniblink108");
    ::mbOnLoadUrlBegin(mbView, handleLoadUrlBegin, nullptr);
    ::mbOnCreateView(mbView, handleCreateView, nullptr);
    ::mbOnJsQuery(mbView, onJsQueryCallback, nullptr);
    ::mbOnClose(mbView, handleWindowClose, nullptr);

    g_hWebViewWnd = mbGetHostHWND(mbView);

    SetRectEmpty(&border_thickness);
    if (GetWindowLongPtr(g_hWebViewWnd, GWL_STYLE) & WS_THICKFRAME)
    {
        AdjustWindowRectEx(&border_thickness, GetWindowLongPtr(g_hWebViewWnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
        border_thickness.left *= -1;
        border_thickness.top *= -1;
    }
    else if (GetWindowLongPtr(g_hWebViewWnd, GWL_STYLE) & WS_BORDER)
    {
        SetRect(&border_thickness, 1, 1, 1, 1);
    }

    MARGINS margins = { 0 };
    DwmExtendFrameIntoClientArea(g_hWebViewWnd, &margins);
    SetWindowPos(g_hWebViewWnd, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);

    long lRet = GetWindowLongPtr(g_hWebViewWnd, GWLP_WNDPROC);

    if (0 == lRet) {
        char szErrorCnt[MAXBYTE] = { 0 };
        sprintf(szErrorCnt, "替换窗口过程出现错误, HWND: %llX, 错误号为:%d", (long long)g_hWebViewWnd, GetLastError());
        MessageBox(NULL, szErrorCnt, NULL, MB_OK);
        return 0;
    }

    g_WebViewWndOldProc = (WEBVIEWWNDPROC)SetWindowLongPtr(g_hWebViewWnd, GWLP_WNDPROC, (long long)MyGameWindowProc);
    // const char* url = "https://www.baidu.com";
    // ::mbLoadURL(mbView, url); // 通过url加载网页
    ::mbLoadHtmlWithBaseUrl(mbView, kHtmlTestStr, "file:///test.html"); // 通过字符串加载html

    ::mbMoveToCenter(mbView);
    ::mbShowWindow(mbView, TRUE);

    ::mbRunMessageLoop(); // 需要退出可调用 mbExitMessageLoop

    return 0;
}
